#include "console.h"
#include "uart.h"
#include "printf.h"
#include <stdint.h>

typedef struct { volatile int locked; } spinlock_t;
static inline void spinlock_acquire(spinlock_t *lk) {
    while (__sync_lock_test_and_set(&lk->locked, 1)) {
        while (lk->locked) { /* busy */ }
    }
}
static inline void spinlock_release(spinlock_t *lk) {
    __sync_lock_release(&lk->locked);
}

static spinlock_t cons_lock = {0};

void consoleinit(void) {
    /* Device init if needed */
}

/* 底层字符输出（不获取锁） */
void consputc(int c) {
    if (c == '\n') {
        uart_putc('\r');
    }
    uart_putc((char)c);
}

/* 线程安全字符串输出（获取锁） */
void console_puts(const char *s) {
    spinlock_acquire(&cons_lock);
    while (*s) consputc(*s++);
    spinlock_release(&cons_lock);
}

/* 无锁字符串输出（调用方需确保线程安全） */
void console_puts_nolock(const char *s) {
    while (*s) consputc(*s++);
}

/* Clear screen + home cursor */
void clear_screen(void) {
    spinlock_acquire(&cons_lock);
    console_puts_nolock("\x1b[2J\x1b[H");
    spinlock_release(&cons_lock);
}

/* Move cursor to (row,col) 1-based */
void goto_xy(int row, int col) {
    char tmp[32];
    int len = snprintf(tmp, sizeof(tmp), "\x1b[%d;%dH", row, col);
    (void)len;  /* 避免未使用变量警告 */
    spinlock_acquire(&cons_lock);
    console_puts_nolock(tmp);
    spinlock_release(&cons_lock);
}

/* Clear to end of line */
void clear_line(void) {
    spinlock_acquire(&cons_lock);
    console_puts_nolock("\x1b[K");
    spinlock_release(&cons_lock);
}

/* 环形缓冲区实现 */
#define CONSOLE_RBUF_SIZE 1024
static char console_rbuf[CONSOLE_RBUF_SIZE];
static int rbuf_head = 0; /* next write index */
static int rbuf_tail = 0; /* next read index */

static inline int rnext(int i) { return (i + 1) % CONSOLE_RBUF_SIZE; }

/* 无锁缓冲区字符写入（调用方需持有锁） */
static int rbuf_putc_nolock(char c) {
    int next = rnext(rbuf_head);
    if (next == rbuf_tail) {
        /* full, drop new byte */
        return 0;
    }
    console_rbuf[rbuf_head] = c;
    rbuf_head = next;
    return 1;
}

/* thread-safe enqueue string */
int console_buffer_puts(const char *s) {
    int written = 0;
    spinlock_acquire(&cons_lock);
    while (*s) {
        if (!rbuf_putc_nolock(*s++)) break;
        written++;
    }
    spinlock_release(&cons_lock);
    return written;
}

/* flush buffer to device (synchronous) */
void console_flush(void) {
    spinlock_acquire(&cons_lock);
    while (rbuf_tail != rbuf_head) {
        consputc(console_rbuf[rbuf_tail]);
        rbuf_tail = rnext(rbuf_tail);
    }
    spinlock_release(&cons_lock);
}
